home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / faq / wdj0597.zip / TECHTIPS.ZIP / MASHLAN.ZIP / BT.TXT < prev   
Text File  |  1997-01-31  |  5KB  |  119 lines

  1. The problem with _beginthread
  2.  
  3. When you develop a multi-threaded application using the Win32 
  4. API, you normally need to use your compiler's run time library 
  5. function called _beginthread, rather than the Win32 API function 
  6. CreateThread.  This is because the run-time library needs to do 
  7. per-thread initialization and cleanup, which it can't do if you 
  8. use the CreateThread API directly.  For instance, if your program 
  9. uses C++ exceptions, the run-time library needs to initialize the 
  10. exception handling mechanism for that thread.  Also, the run-time 
  11. library uses global variables like internally for functions like 
  12. strtok, so the run-time library must allocate and initialize a 
  13. copy of these variables for each thread that uses the RTL.
  14.  
  15. Both CreateThread and _beginthread return a handle to a thread.  
  16. The handle is a magic cookie for an operating system object that 
  17. represents the thread.  This handle can be used to check the 
  18. status of the thread, or it can be used to wait for a thread to 
  19. complete if you use one of the WaitForXXX API functions.  When 
  20. you get the the handle from CreateThread, you are responsible for 
  21. closing the handle using CloseHandle function.  If you don't 
  22. close the handle when you don't need it anymore, you have used up 
  23. part of the operating system's resources which are not going to 
  24. be released until your application terminates.  
  25.  
  26. One of the things that _beginthread does for you is that it 
  27. closes the handle returned by CreateThread when the thread 
  28. terminates, either by returning from the thread function or 
  29. calling _endthread.  This relieves you of the responsibility of 
  30. closing that thread handle.  However, the problem with the handle 
  31. returned by _beginthread is that it is possible that it becomes 
  32. invalid before you use it, because the thread started running 
  33. then terminated.  If you are lucky, the WaitForXXX might return 
  34. an ERROR_INVALID_HANDLE, but sometimes the result is a hang.
  35.  
  36. If you need a valid thread handle from _beginthread, there is a 
  37. workaround.  In the Borland C++ run-time library, there is a 
  38. function called _beginthreadNT, and in the Visual C++ run-time 
  39. library there is a function called _beginthreadex which have 
  40. parameters additional to what _beginthread uses.  One of these 
  41. parameters is the creation flag that is passed to CreateThread.  
  42. This flag can be CREATE_SUSPENDED, which causes the thread not to 
  43. run until you call the ResumeThread function.
  44.  
  45. Once you create a the thread in a suspended state, you can use 
  46. the DuplicateHandle function which creates handle that represents 
  47. the same object as the original handle.  Once you have duplicated 
  48. the handle, you can then allow the thread to run by calling 
  49. ResumeThread.  This needs to be done while the thread is in a 
  50. suspended state because you don't want the thread to run and 
  51. possibly terminate before you get a chance to duplicate the 
  52. original handle.  The handle returned by DuplicateHandle will be 
  53. valid until you close it with CloseHandle.
  54.  
  55. Listing 1 (bt.c) is the source code to a Win32 console mode application
  56. that demonstrates this technique.
  57.  
  58. // listing 1 bt.c
  59. // note - make sure the multi-threaded library option
  60. // is on in your compiler's IDE settings.
  61.  
  62. #include <windows.h>
  63. #include <process.h>
  64. #include <stdio.h>
  65.  
  66. HANDLE beginthread_handle( 
  67. #ifdef __BORLANDC__
  68.    void _USERENTRY (*start_address)(void *),
  69. #else
  70.    unsigned (__stdcall *start_address)(void *),
  71. #endif   
  72.    unsigned stack_size, 
  73.    void *arglist )
  74. {
  75.    DWORD id;
  76.    HANDLE h1 = (HANDLE)
  77. #ifdef __BORLANDC__
  78.         _beginthreadNT(start_address,stack_size,
  79.                 arglist,NULL,CREATE_SUSPENDED,&id);
  80. #else
  81.         // for Visual C++ and compatibles
  82.         _beginthreadex(NULL,stack_size,start_address,
  83.                arglist,CREATE_SUSPENDED,&id);
  84. #endif
  85.    HANDLE h2 = INVALID_HANDLE_VALUE;
  86.    if( h1 != INVALID_HANDLE_VALUE ) {
  87.       DuplicateHandle(GetCurrentProcess(),h1,
  88.           GetCurrentProcess(),&h2,0,FALSE,
  89.           DUPLICATE_SAME_ACCESS);
  90.       ResumeThread(h1); 
  91.    }
  92.    return h2; 
  93. }
  94.  
  95.  
  96. #ifdef __BORLANDC__
  97. void thread( void *arg ) 
  98. #else
  99. unsigned __stdcall thread( void * arg )
  100. #endif
  101. {
  102.    printf("new thread called\n");
  103. #ifndef __BORLANDC__
  104.    return 0;
  105. #endif
  106. }
  107.  
  108.  
  109. int main(void) 
  110. {
  111.    HANDLE h = beginthread_handle(thread,4096,NULL);
  112.    if(h!=INVALID_HANDLE_VALUE) {
  113.        printf("waiting on new thread\n");
  114.        WaitForSingleObject(h,INFINITE);
  115.        printf("new thread is signaled\n");
  116.        CloseHandle(h);
  117.    }
  118.    return 0;
  119. }